package com.anjubao.parking.municipal.parkinglot.controller;

import com.anjubao.parking.municipal.common.dto.ApiCode;
import com.anjubao.parking.municipal.common.dto.ApiResult;
import com.anjubao.parking.municipal.common.global.BusinessCodeEnum;
import com.anjubao.parking.municipal.common.utils.BeanUtils;
import com.anjubao.parking.municipal.common.utils.MunicipalParkingUtils;
import com.anjubao.parking.municipal.parkinglot.dto.*;
import com.anjubao.parking.municipal.parkinglot.feign.ParkingLotFeignService;
import com.anjubao.parking.municipal.parkinglot.form.AreaScreeningParkingLotForm;
import com.anjubao.parking.municipal.parkinglot.form.ParkingLotSlotScreeningForm;
import com.anjubao.parking.municipal.parkinglot.form.PositionScreeningParkingLotForm;
import com.anjubao.parking.municipal.parkinglot.mapper.ParkingLotStatusMapper;
import com.anjubao.parking.municipal.parkinglot.model.ParkingLot;
import com.anjubao.parking.municipal.parkinglot.model.ParkingLotBillRuleRelate;
import com.anjubao.parking.municipal.parkinglot.model.ParkingLotSlot;
import com.anjubao.parking.municipal.parkinglot.model.ParkingLotStatus;
import com.anjubao.parking.municipal.parkinglot.service.*;
import com.anjubao.parking.municipal.parkinglot.util.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.*;
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author anjubao
 */
@RestController
@Api(value = "FeignController", tags = {"feign调用接口"})
@RequestMapping("/feign")
public class FeignController implements ParkingLotFeignService{

    private static final Logger logger = LoggerFactory.getLogger(ParkingLotController.class);

    @Autowired
    private ParkingLotSlotService parkingLotSlotService;

    @Autowired
    private ParkingLotStatusService parkingLotStatusService;
    @Autowired
    private ParkingLotService parkingLotService;
    @Resource
    private ParkingLotBillRuleService parkingLotBillRuleService;
    @Resource
    private ParkingLotBillRuleRelateService parkingLotBillRuleRelateService;
    @Resource
    private ParkingLotStatusMapper parkingLotStatusMapper;

    /**
     * 根据泊位编号查询泊位记录
     * @param code
     * @return
     */
    @ApiOperation(value = "单个泊位记录获取接口", notes = "根据泊位编号获取泊位记录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "泊位编号", dataType = "String"),
    })
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败")
    })
    @GetMapping("/parking-lots-slots/{code}")
    @Override
    public ApiResult<ParkingLotSlotDto> getParkingLotSlotByCode(@PathVariable String code) {
        ParkingLotSlotDto parkingLotSlotDto = parkingLotSlotService.getParkingLotSlotByCode(code);
        return ApiResult.success(parkingLotSlotDto);
    }

    /**
     * 根据泊位code获取停车场信息
     *
     * @param parkingLotSlotCode
     * @return
     */

    @ApiOperation(value = "获取停车场信息", notes = "根据泊位code获取停车场信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "parkingLotSlotCode", value = "泊位编号", dataType = "String"),
    })
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败")
    })
    @GetMapping("/parking-lots-slots/by-parking-lot-slot-code")
    @Override
    public ApiResult<ParkingLotGeomagneticStatusDto> getParkingLotByParkingLotSlotCode(@RequestParam String parkingLotSlotCode) {
        return ApiResult.success(parkingLotSlotService.getParkingLotByParkingLotSlotCode(parkingLotSlotCode));
    }

    @ApiOperation(value = "4.1.3查看单个停车场详细信息接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name="parkingLotCode",value = "停车场code",required = true,dataType = "String",paramType = "path")
    })
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败"),
    })
    /**
     * 查询
     *
     * @param parkingLotCode    停车场编号
     * @return
     */
    @Override
    @GetMapping("/parking-lots/{parkingLotCode}")
    public ApiResult<ParkingLotDto> getParkingLot(@PathVariable String parkingLotCode) {
        logger.info("get parking lot by code {}", parkingLotCode);
        ParkingLot parkingLot = parkingLotService.getById(MunicipalParkingUtils.getIdByCode(parkingLotCode));
        ParkingLotDto parkingLotDto= BeanUtils.transform(ParkingLotDto.class,parkingLot);
        parkingLotDto.setParkingLotCode(parkingLot.getCode());
        return ApiResult.success(parkingLotDto);
    }

    /**
     * 根据名称模糊查询id
     * @param parkingLotSlotName
     * @return
     */
    @ApiOperation(value = "根据名称模糊查询id", notes = "根据名称模糊查询id")
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败")
    })
    @ApiImplicitParams({
            @ApiImplicitParam(name = "parkingLotSlotName", value = "车位名称",dataType = "String")
    })
    @GetMapping("/parking-lots-slots/getParkingLotSlotIdsByName")
    @Override
    public ApiResult<List<ParkingLotSlotDto>> getParkingLotSlotIdsByName( @RequestParam(required = false,name = "parkingLotSlotName") String parkingLotSlotName) {
        logger.info("根据名称模糊查询id {} ");
        List<ParkingLotSlotDto> parkingLotSlotIds = parkingLotSlotService.getParkingLotSlotIdsByName(parkingLotSlotName);
        return ApiResult.success(parkingLotSlotIds);
    }


    /**
     * 根据停车场id获取剩余车位
     * @param parkingLotIds
     * @return
     */
    @ApiOperation(value = "根据停车场id获取剩余车位", notes = "根据停车场id获取剩余车位")
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败")
    })
    @ApiImplicitParams({
            @ApiImplicitParam(name = "parkingLotIds", value = "车位名称",dataType = "String")
    })
    @GetMapping("/parking-lots-status/getSlotStatByParkingLot")
    @Override
    public ApiResult<List<ParkingLotStatusDto>> getSlotStatByParkingLot(@RequestParam List<String> parkingLotIds) {
        List<ParkingLotStatusDto> dtos=parkingLotStatusService.getSlotStatByParkingLot(parkingLotIds);
        return ApiResult.success(dtos);
    }

    /**
     * 更新停车位状态接口
     * @param code
     * @param status
     * @return
     */
    @ApiOperation(value = "更新停车位状态接口", notes = "更新泊位数据")
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败")
    })
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "泊位编号", dataType = "String"),
    })
    @PutMapping("/parking-lots-slots-status/{code}")
    @Override
    public ApiResult<ParkingLotSlotReturnDto> updateParkingLotSlotsStatus(@PathVariable String code, @RequestBody @Valid @ApiParam(value = "泊位信息") Integer status) {
        logger.info("更新泊位信息 {} ", status);
        ParkingLotSlotReturnDto returnDto = parkingLotSlotService.updateParkingLotSlotsStatus(code, status);
        if (returnDto==null){
            return new ApiResult<>(ApiCode.STATUS_INTERNAL_ERROR.getCode(), "泊位名称不能重复");
        }
        return ApiResult.success(returnDto);
    }

    /**
     * 修改停车场空闲车位信息
     *
     * @param parkingLotCode
     * @param freeSlots
     * @return
     */
    @PutMapping("/parking-lots-free/{parkingLotCode}")
    @ApiOperation(value = "4.1.2修改停车场信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name="form",required = true,dataType = "ParkingLotEditForm",paramType = "body"),
            @ApiImplicitParam(name="parkingLotCode",value = "停车场code",required = true,dataType = "String",paramType = "path")
    })
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败"),
    })
    @Override
    public ApiResult<ParkingLotReturnCodeDto> updateParkingLotFree(@PathVariable String parkingLotCode, @RequestBody @Valid Integer freeSlots) {
        logger.info("updating parking lot {} ", freeSlots);
        ParkingLotReturnCodeDto parkingLotReturnCodeDto = parkingLotStatusService.updateParkingLotFree(parkingLotCode, freeSlots);
        return ApiResult.success(parkingLotReturnCodeDto);
    }

    /**
     * 查询
     *
     * @param form
     * @return
     */
    @GetMapping("/areas")
    @ApiOperation(value = "4.1.5根据省市区筛选停车场信息接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name="parkingLotType",value = "停车场类型(1:封闭式停车场，2:路内停车场)", dataType = "int" ,paramType = "query",allowableValues = "1,2",type = "integer"),
            @ApiImplicitParam(name="parkingLotStatus",value = "停车场状态(0:正常,1:禁用)", dataType = "int" ,paramType = "query",allowableValues = "0,1",type = "integer"),
            @ApiImplicitParam(name="parkingStatus",value = "车位状态 0:车位不足 1:有位 2:已满", dataType = "int" ,paramType = "query",allowableValues = "0,1,2",type = "integer")
    })
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败"),
    })
    @Override
    public ApiResult<List<ParkingLotDto>> areaScreeningParkingLot( AreaScreeningParkingLotForm form) {
        if(form.getCityId()==null&&form.getDistrictId()==null&&form.getProvinceId()==null){
            return new ApiResult<>(ApiCode.STATUS_INTERNAL_ERROR.getCode(), "省市区ID不允许同时为空");
        }
        logger.info("screening parking lot by conditions {}", form);
        Page<ParkingLotDto> page=new Page<>();
        page.setSize(form.getPageSize());
        page.setCurrent(form.getPage());
        IPage<ParkingLotDto> parkingLotLists = parkingLotService.areaScreeningParkingLot(page,form);
        return ApiResult.success(parkingLotLists.getRecords(), (int) parkingLotLists.getTotal());
    }

    /**
     * 获取泊位数据,并分页
     * @param form
     * @return
     */
    @ApiOperation(value = "搜索泊位列表接口", notes = "获取泊位数据")
    @ApiResponses(value = {
            @ApiResponse(code = 5000, message = "操作失败")
    })
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "页号",dataType = "int"),
            @ApiImplicitParam(name = "pageSize", value = "页大小",dataType = "int"),
    })
    @GetMapping("/parking-lots-slots")
    @Override
    public ApiResult<List<ParkingLotSlotDto>> getParkingLotSlots(ParkingLotSlotScreeningForm form) {
        logger.info("获取泊位分页数据 {} ");
        Page<ParkingLotSlotDto> parkingLotSlots = parkingLotSlotService.getParkingLotSlots(1,9999,form);
        System.out.println("============="+ ObjectSizeCalculator.getObjectSize(parkingLotSlots));
        return ApiResult.success(parkingLotSlots.getRecords(),(int)parkingLotSlots.getTotal());
    }

    @GetMapping("/parking-lots-bill-rules/parking-total-fee")
    @Override
    @ApiOperation("停车总费用")
    public ApiResult<ParkingTotalFeeDto> getParkingTotalFee(@ApiParam(value = "停车场code",required = true) @RequestParam(value = "parkingLotCode",required = true) String parkingLotCode,
                                                            @ApiParam(value = "进场时间",required = true) @RequestParam(value = "enterTime",required = true) LocalDateTime enterTime,
                                                            @ApiParam(value = "离场时间",required = true) @RequestParam(value = "leaveTime",required = true) LocalDateTime leaveTime) {

        return  ApiResult.success(parkingLotBillRuleService.getParkingTotalFee(parkingLotCode,enterTime,leaveTime));
    }

    @GetMapping("/parking-lots-bill-rules/parking-total-fee-string")
    @ApiOperation("停车总费用 时间类型为string")
    public ApiResult<ParkingTotalFeeDto> getParkingTotalFeeWithString(@ApiParam(value = "停车场code",required = true) @RequestParam(value = "parkingLotCode",required = true) String parkingLotCode,
                                                                      @ApiParam(value = "进场时间",required = true) @RequestParam(value = "enterTime",required = true) String enterTime,
                                                                      @ApiParam(value = "离场时间",required = true) @RequestParam(value = "leaveTime",required = true) String leaveTime){

        return ApiResult.success(parkingLotBillRuleService.getParkingTotalFee(parkingLotCode, DateUtil.string2LocalDateTime(enterTime),DateUtil.string2LocalDateTime(leaveTime)));
    }


    @PostMapping("/parking-lots-bill-rules/parking-total-fee/batch")
    @ApiOperation("批量计算停车总费用")
    public ApiResult<List<ParkingTotalFeeDto>> getParkingTotalFeeBatch(@RequestBody List<ParkingTotalFeeDto> totalFeeList){

        return ApiResult.success(parkingLotBillRuleService.getParkingTotalFeeBatch(totalFeeList));
    }

    @GetMapping("/find-parking-lot")
    @ApiOperation(value = "4.1.4根据经纬度筛选停车场信息接口/找车位")
    public ApiResult<List<ParkingLotDto>> findParkingLot(@ApiParam(value = "经度",required = true) @RequestParam(value = "latitude",required = true) Double latitude,
                                                         @ApiParam(value = "纬度",required = true) @RequestParam(value = "longitude",required = true) Double longitude){

        return ApiResult.success(parkingLotService.findParkingLot(latitude,longitude));
    }

    @Override
    @GetMapping("/parkinglot/search")
    @ApiOperation(value = "搜索停车场")
    public ApiResult<List<ParkingLotDto>> searchParkinglot(@ApiParam(value = "停车场名称/位置",required = true) @RequestParam(value = "name",required = true) String name,
                                                           @ApiParam(value = "latitude",required = true) @RequestParam(value = "latitude",required = true) Double latitude,
                                                           @ApiParam(value = "longitude",required = true) @RequestParam(value = "longitude",required = true) Double longitude) {

        return ApiResult.success(parkingLotService.searchParkingLot(name ,latitude,longitude));
    }

    @Override
    @GetMapping("/parkinglot/billrule")
    @ApiOperation(value = "通过停车位查询计费规则")
    public ApiResult<ParkingLotBillRuleDto> getBillRule(@ApiParam(value = "车位编号",required = true) @RequestParam(value = "parkinglotSlotName",required = true) String parkinglotSlotName) {

        return ApiResult.success(parkingLotBillRuleService.getBillRuleByParkingLotSlotName(parkinglotSlotName));
    }

    /**
     * 计算两经纬度点之间的距离（单位：米）
     * @param lng1  经度
     * @param lat1  纬度
     * @param lng2
     * @param lat2
     * @return
     */
    public static double getDistance(double lng1,double lat1,double lng2,double lat2){
        double radLat1 = Math.toRadians(lat1);
        double radLat2 = Math.toRadians(lat2);
        double a = radLat1 - radLat2;
        double b = Math.toRadians(lng1) - Math.toRadians(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1)
                * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * 6378137.0;// 取WGS84标准参考椭球中的地球长半径(单位:m)
        s = Math.round(s * 10000) / 10000;
        return s;
    }

    /**
     * 批量更新停车场空闲车位信息
     * @param parkingLotStatusDtoList
     * @return
     */
    @PutMapping("/parking-lots-free/list")
    @Override
    public ApiResult<Integer> updateParkingLotFreeList(@RequestBody List<ParkingLotStatusDto> parkingLotStatusDtoList){
        Integer returnNum= parkingLotStatusService.updateFreeList(parkingLotStatusDtoList);
        return ApiResult.success(returnNum);
    }
}
